const _ = require('lodash')
const ObjectId = require('mongodb').ObjectId

// 初始化个人文件夹名称
const INIT_DIRNAME = '云盘'
const ERR_PARAMS = {msg: '参数有误'}
const ERR_EXIST = {msg: '数据已存在'}
// 过滤掉接口不需要返回的字段
const FILTER_PARAMS = {
    _id: 0,
    __v: 0
}

const MENU_TYPE = [
    // 全部文件 图片 文档 视频 音乐  其他
    {name: '全部文件', type: 'all', index: 999},
    {name: '图片', type: 'image', index: 0},
    {name: '文档', type: 'docs', index: 1},
    {name: '视频', type: 'video', index: 2},
    {name: '音乐', type: 'music', index: 3},
    {name: '其他', type: 'other', index: 4}
]

const INIT_PAGE_SIZE = 10, INIT_PAGE_INDEX = 1;

module.exports = app => {
    class MenuService extends app.Service {

        /**
         * 获取分类菜单
         * @return {Array} 分类菜单 
         */
        async classify(){
            try {
                return new Promise((resolve, reject) => {
                    resolve(MENU_TYPE)
                })
            } catch (error) {
                console.log(error)
            }
        }

        /**
         * 获取指定分类菜单的文件列表
         * @param {String} fileType 分类type
         * @return {Array} 分类菜单 
         */
        async getClassify(data){
            try {
                let { 
                    fileType, 
                    pageSize = INIT_PAGE_SIZE, 
                    pageIndex = INIT_PAGE_INDEX
                } = data
                if(fileType === 'all' || !fileType){
                    fileType = ''
                }
                let query = fileType ? {fileType:fileType} : {}
                return new Promise((resolve, reject) => {
                    this.ctx.model.File.find(query,FILTER_PARAMS)
                    .skip(Number(pageIndex)).limit(Number(pageSize))
                    .sort({'_id':-1}).lean()
                    .exec((err, res) => {
                        if (err) {
                            reject(err) 
                        } else {
                            resolve(res) 
                        }
                    }) 
                })
            } catch (error) {
                console.log(error)
            }
        }

        /**
         * 获取菜单树列表
         * @param {String} userId 用户id
         * @param {String} dirId 文件夹id
         */
        async list(data) {
            try {
                return new Promise((resolve, reject) => {
                    data.userId = this.ctx.state.user.id
                    this.ctx.model.Menu.find({...data},FILTER_PARAMS).lean().exec((err, res) => {
                        if (err) {
                            reject(err) 
                        } else {
                            resolve(res) 
                        }
                    }) 
                })
            } catch (error) {
                console.log(error)
            }
        }

        /**
         * 新增一个文件夹 
         * @param {String} dirName 新增文件夹名称
         * @param {String} parentId 父级文件夹id
         * 
         * 初始化菜单树时， 不需要传入 parentId
         */
        async addDir (data) {
            try {
                return new Promise(async (resolve, reject) => {
                    if(!data.parentId && !data.dirName){
                        data.dirName = INIT_DIRNAME
                    }

                    data.dirId = new ObjectId() // 防止id重复
                    let current = await this.saveDir(data)

                    if(data.parentId){
                        // 判断父级是否存在
                        let parent = await this.getDir(data.parentId)
                        if(parent){
                            let cloneData = _.cloneDeep(parent)
                            cloneData.children.push(current)
                            console.log(parent, cloneData)
                            await this.update(parent, cloneData)
                        }
                    }
                    resolve(current)
                })
            } catch (error) {
                console.log(error)
            }
        }


        /**
         * 删除一个文件夹（使用文件夹id） 需要同时删除父级的children
         * @param {String} dirId 删除文件夹的id
         */
        async removeDir (dirId){
            try {
                return new Promise(async (resolve, reject) => {
                    let current = await this.getDir(dirId)
                    let userId = this.ctx.state.user.id
                    this.ctx.model.Menu.deleteOne({ dirId,userId })
                    .lean().exec(async (err, res) => {
                        if (err) {
                            reject(err) 
                        } else {
                            if(current && current.parentId){
                                let parent = await this.getDir(current.parentId)
                                let cloneData = _.cloneDeep(parent)
                                _.remove(cloneData.children, (n) => n.dirId === dirId);
                                await this.update(parent, cloneData)
                            }
                            resolve(res) 
                        }
                    }) 
                    
                })
            } catch (error) {
                console.log(error)
            }
        }
        async saveDir (data){
            try{
                return new Promise(async (resolve, reject) => {
                    data.type = 'dir'  // 默认是文件夹类型 值为 dir
                    data.userId = this.ctx.state.user.id
                    this.ctx.model.Menu({...data})
                    .save((err, res) => {
                        if (err) {
                            reject(err) 
                            return
                        }
                        resolve(res)
                    }) 
                })
            }catch(error){
                console.log(error)
            }
        }

        async update (oldData = {}, newData){
            return new Promise((resolve, reject) => {
                this.ctx.model.Menu.updateOne(oldData, newData).lean().exec((err, docs) => {
                    if (err) {
                        reject(err) 
                    } else {
                        resolve(docs) 
                    }
                }) 
            })
        }

        /**
         * 查找一个文件夹（使用文件夹id）
         * @param {String} dirId 查找文件夹的id
         * @return {Object} 查找到的对象
         */
        async getDir (dirId){
            try {
                return new Promise((resolve, reject) => {
                    let userId = this.ctx.state.user.id
                    this.ctx.model.Menu.findOne({dirId,userId})
                    .lean().exec((err, docs) => {
                        if (err) {
                            reject(err) 
                        } else {
                            resolve(docs) 
                        }
                    }) 
                })
            } catch (error) {
                console.log(error)
            }
        }
        /**
         * 查找一个文件夹（使用用户id）
         * @param {String} userId (可不传)默认返回当前用户 查找用户的id
         * @return {Promise} 查找到的对象
         */
        async getUserDir (userId){
            try {
                return new Promise((resolve, reject) => {
                    if(!userId){
                        userId = this.ctx.state.user.id
                    }
                    this.ctx.model.Menu.findOne({userId}, {
                        _id: 0,
                        __v: 0
                    }).lean().exec((err, docs) => {
                        if (err) {
                            reject(err) 
                        } else {
                            resolve(docs) 
                        }
                    }) 
                })
            } catch (error) {
                console.log(error)
            }
        }

        /**
         * 支持文件/文件夹 单个或多个删除
         */
        async delete (data){
            try {
                return new Promise(async (resolve, reject) => {
                    if(Array.isArray(data) && data.length >= 0){
                        // 删除多个
                        let res = []
                        for(let k = 0; k < data.length; k++){
                            let result = await this.deleteOne(data[k])
                            res.push(result)
                        }
                        resolve(res)
                    }else{
                        // 删除单个
                        let res = await this.deleteOne(data)
                        resolve(res)
                    }
                })
            } catch (error) {
                console.log(error)
            }
        }

        async deleteOne (data){
            try {
                return new Promise(async (resolve, reject) => {
                    if(data.dirId){
                        let res = await this.removeDir(data.dirId)
                        resolve(res)
                    }else if(data.fileId){
                        let res = await this.ctx.service.file.remove(data.fileId)
                        resolve(res)
                    }
                })
            } catch (error) {
                console.log(error)
            }
        }

        /**
         * 重命名一个文件/文件夹
         * @param {String} ? dirId 文件/文件夹id
         * @param {String} ? fileId 文件/文件夹id
         * @param {String} ? parentId 父级文件夹id
         * @param {String} oldName 旧名称
         * @param {String} newName 新名称
         */
        async rename (data){
            try {
                return new Promise(async (resolve, reject) => {
                    const { dirId, fileId, oldName, newName} = data
                    let userId = this.ctx.state.user.id
                    if(dirId){
                        let parentId = data.parentId
                        let res = await this.update(
                            {userId,dirId,parentId,dirName: oldName},
                            {dirName: newName}
                        )
                        resolve(res)
                    }else if(fileId){
                        let res = await this.ctx.service.file.update(
                            {userId,fileId,fileName: oldName},
                            {fileName: newName}
                        )
                        resolve(res)
                    }else{
                        reject()
                    }
                })
            } catch (error) {
                console.log(error)
            }
        }
    }
    return MenuService
}
